#include "StdAfx.h"
#include "ParseParam.h"

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/foreach.hpp>
#include <boost/phoenix/statement/if.hpp>
#include<sstream>
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
//namespace ascii = boost::spirit::ascii;
namespace standard = boost::spirit::standard;
using boost::spirit::ascii::space;


template<typename Iterator>
struct CommentSkipper : public qi::grammar<Iterator> {

	qi::rule<Iterator> skip;

	CommentSkipper() : CommentSkipper::base_type(skip, "PL/0")
	{
		using standard::char_;
		skip =  qi::eol | standard::blank | qi::lit("#") >> *(char_ - qi::eol) >> qi::eol;
	}
};

struct suData
{
	string m_strParamName;
	string m_strParamValue;
	int m_iData;
	double m_fData;
	int m_iDataType;
};
BOOST_FUSION_ADAPT_STRUCT(
	suData,
	(std::string, m_strParamName)
	(std::string, m_strParamValue)
	(int, m_iData)
	(double, m_fData)
	(int, m_iDataType)
	)

struct suParam
{
	string m_strParamName;
	vector<suData> m_vData;
};
BOOST_FUSION_ADAPT_STRUCT(
	suParam,
	(std::string, m_strParamName)
	(std::vector<suData>, m_vData)
	);

struct suStruct
{
	string m_strStructName;
	std::vector<suParam> m_vParam;
};

BOOST_FUSION_ADAPT_STRUCT(
	suStruct,
	(std::string, m_strStructName)
	(std::vector<suParam>, m_vParam)

	);

struct suPacket
{
	string m_strPacketName;
	int m_style;
	string m_last_modified;
	vector<suStruct> m_vParam;
	int iCheckSum;
};

BOOST_FUSION_ADAPT_STRUCT(
	suPacket,
	(std::string, m_strPacketName)
	(int, m_style)
	(std::string, m_last_modified)
	(std::vector<suStruct>, m_vParam)
	(int, iCheckSum)
	);

template <typename Iterator, typename Skipper = CommentSkipper<Iterator>>
struct ParseCfgPacket : qi::grammar<Iterator, suPacket, Skipper>
{
	ParseCfgPacket() :ParseCfgPacket::base_type(m_ruleParsePacket, "xml")
	{
		using standard::char_;
		using qi::eol;
		using namespace qi::labels;
		using qi::on_error;
		using phoenix::construct;
		using phoenix::val;
		using qi::lexeme;
		using boost::spirit::qi::attr;

		m_ruleStr%=lexeme[+(qi::char_ - '#' -qi::eol-qi::blank) ];
		m_ruleParamName %= lexeme[+(qi::char_ - '#' - qi::eol - qi::blank - '=')];
		m_ruleStrValue %= (lexeme['"' >> *(char_ - '"') >> '"']);
		m_ruleIntData %= (qi::int_parser<int>());
		m_ruleRealData %= (qi::real_parser<double, qi::strict_real_policies<double>>());

		m_ruleParseKeyAndValue %=
			m_ruleParamName[phoenix::at_c<4>(_val)= -1][phoenix::at_c<1>(_val) = ""][phoenix::at_c<2>(_val) = 0][phoenix::at_c<3>(_val) = 0] >>
			"=" >
			(
			m_ruleStrValue[phoenix::at_c<4>(_val)=0][phoenix::at_c<1>(_val) = _1]||
			m_ruleRealData[phoenix::at_c<4>(_val)= 1][phoenix::at_c<3>(_val)=_1]||
			m_ruleIntData[phoenix::at_c<4>(_val)= 2][phoenix::at_c<2>(_val)=_1]
		);

		m_ruleParseParam %=
			"PARAM" >> m_ruleStr >>
			*(m_ruleParseKeyAndValue) >>
			"ENDPARAM";

		m_ruleParseStruct %=
			"STRUCTURE" >> m_ruleStr >>
			+(m_ruleParseParam)>>
			"ENDSTRUCTURE";

		m_ruleParsePacket%=
			"PACKET">>m_ruleStr>>
			"style">>m_ruleIntData>>
			"last_modified">>m_ruleStr>>
			*(m_ruleParseStruct)>>"ENDPACKET">>
			"checksum">>*("0")>>*("x")>>qi::int_parser<int, 16U>();

		on_error<qi::fail>
			(
			m_ruleParseParam
			, m_strdata
			<< val("Error! Expecting ")
			<< _4                               // what failed?
			<< val(" here: \"")
			<< construct<std::string>(_3, _2)   // iterators to error-pos, end
			<< val("\"")
			<<"\r\n"
			);

		on_error<qi::fail>
			(
			m_ruleParsePacket
			, m_strdata
			<< val("Error! Expecting ")
			<< _4                               // what failed?
			<< val(" here: \"")
			<< construct<std::string>(_3, _2)   // iterators to error-pos, end
			<< val("\"")
			<<"\r\n"
			);
	}
	string GetErrorInfo()
	{
		return m_strdata.str();
	}
private:
	qi::rule<Iterator, std::string(), Skipper> m_ruleStr;
	qi::rule<Iterator, std::string(), Skipper> m_ruleParamName;
	qi::rule<Iterator, std::string(), Skipper> m_ruleStrValue;
	qi::rule<Iterator, int, Skipper> m_ruleIntData;
	qi::rule<Iterator, double, Skipper> m_ruleRealData;
	qi::rule<Iterator, suData(),Skipper> m_ruleParseKeyAndValue;
	qi::rule<Iterator, suParam,Skipper> m_ruleParseParam;
	qi::rule<Iterator, suStruct,Skipper> m_ruleParseStruct;
	qi::rule<Iterator, suPacket,Skipper> m_ruleParsePacket;

	std::stringstream m_strdata;
};

void Parse(const string& str, suParamString& param)
{
	suPacket data;
	ParseCfgPacket<std::string::const_iterator> parse;
	CommentSkipper<std::string::const_iterator> skipper;

	string strModiy = str;
	std::string::iterator pos = strModiy.begin();
	clock_t t0, t1;
	t0 =clock();
	phrase_parse(pos, strModiy.end(), parse, skipper, data);
	t1 =clock();
	string strError = parse.GetErrorInfo();
	data = data;
	printf("%d", t1-t0);
}